/****************************************************
	文件：PlannerWeightedTree.cs
	作者：林文豪
	日期：2021/03/21 19:17:25
	功能：1、根据 Agent 中所有的 Goals 和 Actions 对所有 Goals 进行初始化，创建一颗多叉树
          2、实现基接口的 GetPlan 方法，找到从 from 结点到 to 结点的 Cost 之和最小的一组结点
*****************************************************/
using System;
using System.Collections.Generic;

namespace MyGame.AI.GOAP {
    public class PlannerWithMultiwayTree : IPlanner {
        private Dictionary<IGoal, MultiwayTree> _GoalMap; // Goal与多叉树的一一映射关系
        private List<INode>                     _Plan;
        private List<IAction>            _UsingActions;

        public Dictionary<IGoal, MultiwayTree> GoalMap => _GoalMap;

        public PlannerWithMultiwayTree(List<IGoal> allGoals, List<IAction> allActions) {
            _GoalMap = new Dictionary<IGoal, MultiwayTree>();
            for (int i = 0; i < allGoals.Count; i++) {
                MultiwayTree multiwayTree = GoapFactory.Instance.GenerateMultiwayTree(allGoals[i], allActions);
                _GoalMap.Add(allGoals[i], multiwayTree);
            }
        }

        public MultiwayTree GetMultiwayTreeTree(string goalName) {
            IGoal goal = null;
            foreach (IGoal goalMapKey in _GoalMap.Keys) {
                if (goalMapKey.GetNodeName() == goalName) {
                    goal = goalMapKey;
                    break;
                }
            }

            if (goal!=null) {
                return _GoalMap[goal];
            }
            return null;
        }

        // TODO : 寻找到达Goal的所有通路
        public List<IAction> GetPlan(IGoal to) {
            List<IAction> result = new List<IAction>();
            // MultiwayTreeNode bestTreeNode = GetBestPlan(_GoalMap[to].FindLeafNodes());
            //
            // while (bestTreeNode.Parent != null) {
            //     result.Add(bestTreeNode.Content);
            //     bestTreeNode = bestTreeNode.Parent;
            // }
            //
            return result;
        }
        
        public void FrameFunc() {
            // TODO ： 这里更新的是影响Action中Cost取值的相关数据的变化，例如与Move相关的Distance，与Attack相关的威胁程度等等
            foreach (IAction usingAction in _UsingActions) {
                usingAction.FrameFunc();
            }
        }

        // TODO : 寻找最佳通路
        private MultiwayTreeNode GetBestPlan(List<MultiwayTreeNode> allPlan) {
            MultiwayTreeNode bestNode = null;
            int              minCost  = int.MaxValue;
            for (int i = 0; i < allPlan.Count; i++) {
                int totalCost = 0;
                while (allPlan[i].Parent != null) {
                    allPlan[i] = allPlan[i].Parent;
                }
                if (totalCost < minCost) {
                    minCost  = totalCost;
                    bestNode = allPlan[i];
                }
            }

            return bestNode;
        }

        private List<List<MultiwayTreeNode>> FindPossibleLeafNode(IGoal goal) {
            // 用世界状态与所有叶子结点的Pre比较，遇到满足的就返回一个List
            List<List<MultiwayTreeNode>> result = new List<List<MultiwayTreeNode>>();

            List<MultiwayTreeNode> leafNodes = _GoalMap[goal].LeafNodes;
            foreach (MultiwayTreeNode leafNode in leafNodes) {
                MultiwayTreeNode tempLeafNode = leafNode;
                while (tempLeafNode.Parent != null) {
                    // TODO : 用世界状态与当前节点的Pre相比较
                    if (true) {
                        List<MultiwayTreeNode> nodesToHead = _GoalMap[goal].GetNodesToGoal(tempLeafNode);
                        result.Add(nodesToHead);
                        break;
                    }
                    tempLeafNode = tempLeafNode.Parent;
                }
            }

            return result;
        }
    }
}
